﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;

namespace CondeNetUK.Imaging.Filters
{
    public unsafe class UnsharpMasker
    {
        public static unsafe Bitmap UnsharpMask(Bitmap img, double amount, int radius, int threshold)
        {
            if (amount > 500) amount = 500;
            amount = amount * 2;
            if (radius > 50) radius = 50;
            radius = radius * 2;
            if (threshold > 255) threshold = 255;

            if (radius == 0)
            {
                img.Dispose();
                return img;
            }
            int w = img.Width;
            int h = img.Height;
            Bitmap imgCanvas = new Bitmap(w, h);
            Bitmap imgBlur = new Bitmap(w, h);

            for (int i = 0; i < radius; i++)
            {
                Helpers.ConvMatrix con = new Helpers.ConvMatrix();
                imgBlur = (Bitmap)img.Clone();
                Helpers.Conv3x3(imgBlur, con);
            }

            BitmapData imgdata1 = img.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData imgdata2 =
                imgBlur.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            byte* p1 = (byte*)(void*)imgdata1.Scan0;

            byte* p2 = (byte*)(void*)imgdata2.Scan0;

            if (threshold > 0)
            {
                for (int x = 0; x < w - 1; x++)
                {
                    for (int y = 0; y < h; y++)
                    {
                        int imgRValue = p1[2];
                        int imgGValue = p1[1];
                        int imgBValue = p1[0];

                        int imgBlurRValue = p2[2];
                        int imgBlurGValue = p2[1];
                        int imgBlurBValue = p2[0];


                        int rNew = (Math.Abs(imgRValue - imgBlurRValue) >= (int)threshold)
                                       ? Math.Max(0, Math.Min(255, ((int)amount * (imgRValue - imgBlurRValue)) + imgRValue))
                                       : imgRValue;
                        int gNew = (Math.Abs(imgGValue - imgBlurGValue) >= (int)threshold)
                                       ? Math.Max(0, Math.Min(255, ((int)amount * (imgGValue - imgBlurGValue)) + imgGValue))
                                       : imgGValue;
                        int bNew = (Math.Abs(imgBValue - imgBlurBValue) >= (int)threshold)
                                       ? Math.Max(0, Math.Min(255, ((int)amount * (imgBValue - imgBlurBValue)) + imgBValue))
                                       : imgBValue;

                        if ((imgRValue != rNew) || (imgGValue != gNew) || (imgBValue != bNew))
                        {
                            p1[0] = (byte)bNew;
                            p1[1] = (byte)gNew;
                            p1[2] = (byte)rNew;
                        }
                        p1 = p1 + 3;
                        p2 = p2 + 3;
                    }
                }
            }
            else
            {
                img.UnlockBits(imgdata1);
                imgBlur.UnlockBits(imgdata2);
                for (int x = 0; x < w; x++)
                {
                    for (int y = 0; y < h; y++)
                    {
                        
                        //Bitmap imgClone = img.Clone() as Bitmap;
                        System.Drawing.Color rgb = img.GetPixel(x, y);
                        int imgRValue = Convert.ToInt32(rgb.R);
                        int imgGValue = Convert.ToInt32(rgb.G);
                        int imgBValue = Convert.ToInt32(rgb.B);

                        System.Drawing.Color imgBlurRGB = imgBlur.GetPixel(x, y);
                        int imgBlurRValue = Convert.ToInt32(imgBlurRGB.R);
                        int imgBlurGValue = Convert.ToInt32(imgBlurRGB.G);
                        int imgBlurBValue = Convert.ToInt32(imgBlurRGB.B);

                        int rNew = ((int)amount * (imgRValue - imgBlurRValue)) + imgRValue;

                        if (rNew > 255)
                            rNew = 255;
                        else if (rNew < 0)
                            rNew = 0;

                        int gNew = ((int)amount * (imgGValue - imgBlurGValue)) + imgGValue;

                        if (gNew > 255)
                            gNew = 255;
                        else if (gNew < 0)
                            gNew = 0;

                        int bNew = ((int)amount * (imgBValue - imgBlurBValue)) + imgBValue;
                        if (bNew > 255)
                            bNew = 255;
                        else if (bNew < 0)
                            bNew = 0;

                        try
                        {
                            img.SetPixel(x, y, System.Drawing.Color.FromArgb(rNew, gNew, bNew));
                        }
                        catch
                        {
                        }
                    }
                }
            }

            

            return img;
        }
    }
}
